#include "exchangescanner.h"

#include <iostream>
#include <QSettings>
#include <QSqlQuery>

ExchangeScanner::ExchangeScanner(QObject *parent)
    : QObject{parent}
{
    /*连接sqlite和sql server数据库*/
    connectSqlite();
    connectSqlServer();

    /*
     * 在子线程扫描类的构造函数中，进行一次sqlite的exchange_tag查询，目的是将sqlite内表结构
     * 映射到 QList<ExchangeTag * >结构里来，由app来持有结构，这部分操作执行后，scanner类
     * 持有交换信号数据结构
    */

//    exchangeTagListString = "";

    QSqlQuery query(multithreadCalculationSqliteConnection);
    query.exec("select * from exchange_tag");
    while(query.next()) {
        exchangeTagPropertyMap.insert(query.value(2).toString(), new ExchangeTagEntity(nullptr, query.value(0).toInt(),
                                                                                       query.value(1).toString(), query.value(2).toString(),
                                                                                       query.value(3).toString(), 0.0, &multithreadCalculationSqliteConnection,
                                                                                       &multithreadCalculationSqlserverConnection));
//        exchangeTagListString += query.value(2).toString() + ", ";
    }
//    exchangeTagListString = exchangeTagListString.mid(0, exchangeTagListString.size()-2) + " ";
}

ExchangeScanner::~ExchangeScanner()
{
    multithreadCalculationSqliteConnection.close();
    multithreadCalculationSqlserverConnection.close();
    std::cout << "multithread sqlite & sql server closed" << std::endl;
}

void ExchangeScanner::startScan()
{
    /*
     * 这个函数的动作是进行扫描前的准备工作
     * 1. 初始化计时器
     * 2. 连接计时器定时触发和槽函数
     * 3. 拼接了一下交换信号点名字符串，目的是为接下来的循环sql语句做准备（次要内容）
     * 4. 开启计时器循环
    */

    // 创建计时器
    scanTimer = new QTimer(this);

    //将计时器的到时信号与当前类到时槽函数
    connect(scanTimer, &QTimer::timeout, this, &ExchangeScanner::scan);

    //DONE:1. 获取Map<"DI1_14", [00:00:00, 01:00:00.....]>, Map<"DI1_15", [00:30:00, 01:30:00.....]>....
    generateExchangeTagCycleMap();

    //将计时器设定为1秒
    scanTimer->start(1000);
    std::cout << "Thread start, scan exchange symbol start..." << std::endl;
}

/*
 * 扫描函数的内部逻辑：用当前时间在sqlite的交换信号时间配置表里查找，只要查到了当前时间比交换时间正好度过了
 * 1分钟，即开始计算，开始计算选择使用QT信号槽机制，将计算标志位置为1.0，计算结束之后由计算函数将标志位置0.0
 *
 * 1. 获取当前时间戳，将时间戳的ms位置为000，此目的是为了匹配BCMS_COL的时间戳结构
 * 2. 在交换信号时间Map上建立iterator，用当前的时间戳向前找1分钟，找到交换信号
*/
void ExchangeScanner::scan()
{
    QTime currentTimeStamp = QTime::currentTime();
    QTime currentTime(currentTimeStamp.hour(), currentTimeStamp.minute(), currentTimeStamp.second());
    qDebug() << currentTime;

    QMap<QString, QList<QTime>>::iterator CycleIter;
    for(CycleIter=exchangeTagTimeCycleMap.begin(); CycleIter!=exchangeTagTimeCycleMap.end();++CycleIter) {
        for(int index = 0; index < CycleIter.value().size(); ++index) {
            if(currentTime.addSecs(-60) == CycleIter.value()[index]) {
                qDebug() << "exchange happened 60 seconds ago on: " + CycleIter.key();
                exchangeTagPropertyMap.value(CycleIter.key())->setReal(1.0);
            }
        }
    }
}

void ExchangeScanner::stopScan()
{
    std::cout << "Thread quit, scan exchange symbol stop." << std::endl;
    scanTimer->stop();
}

void ExchangeScanner::connectSqlite()
{
    /*
     * 在当前扫描thread内，进行sqlite连接
    */
    multithreadCalculationSqliteConnection = QSqlDatabase::addDatabase("QSQLITE", "thread_sqlite_connection");
    multithreadCalculationSqliteConnection.setDatabaseName("bfmt.db");
    bool sqliteOpenFlag = multithreadCalculationSqliteConnection.open();
    if(sqliteOpenFlag) {
        std::cout << "thread success connect property sqlite database..." << std::endl;
    } else {
        std::cout << "thread error connect property sqlite database..." << std::endl;
    }
}

void ExchangeScanner::connectSqlServer()
{
    /*
     * 根据config.ini的内容进行sql server连接，意味着在现场调试程序时，需要对config.ini进行配置，并且需要配置ODBC
     * 这个QSqlDatabase * sqliteConnection的传递表示我传过来的是一个sqliteConnection,并且可以当作
    */
    //读取config.ini文件内容，准备进行sql server ODBC连接
    QSettings setting("./config.ini", QSettings::IniFormat);
    QString sqlserverODBC = setting.value("SqlServer/ODBC").toString();
    QString sqlserverDATABASE = setting.value("SqlServer/DATABASE").toString();
    QString sqlserverUSERNAME = setting.value("SqlServer/USERNAME").toString();
    exchangeTableNameInSqlServer = setting.value("SqlServer/EXCHANGETABLE").toString();

    /*
     * 在当前thread内，进行sql server 数据连接
     */
    multithreadCalculationSqlserverConnection = QSqlDatabase::addDatabase("QODBC", "thread_sql_server_connection");
    multithreadCalculationSqlserverConnection.setDatabaseName(sqlserverODBC + ";DATABASE="+sqlserverDATABASE);
    multithreadCalculationSqlserverConnection.setUserName(sqlserverUSERNAME);

    bool sqlserverOpenFlag = multithreadCalculationSqlserverConnection.open();
    if(sqlserverOpenFlag) {
        std::cout << "thread success connect sql server database..." << std::endl;
    } else {
        std::cout << "thread error connect sql server database..." << std::endl;
    }
}

void ExchangeScanner::generateExchangeTagCycleMap()
{
    QSqlQuery query(multithreadCalculationSqliteConnection);
    QString selectQuery = "select DI1_14, DI1_15, DI2_14, DI2_15 from exchange_tag_cycle";
    query.exec(selectQuery);

    QList<QString> tagList = {"DI1_14", "DI1_15", "DI2_14", "DI2_15"};
//    QMap<QString, QList<QTime>> tagMap;

    while(query.next()) {
        for(int i=0;i<tagList.length();i++) {
            QTime time = QTime::fromString(query.value(i).toString(), "hh:mm:ss");
            exchangeTagTimeCycleMap[tagList[i]].append(time);
        }
    }
}
